package com.jichangxiu.framework.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.jichangxiu.common.annotation.Dynamic;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.common.context.JcxContext;
import com.jichangxiu.framework.utils.DynamicUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Slf4j
@Aspect
@Component
public class DynamicAspect {

    @Pointcut("@within(com.jichangxiu.common.annotation.Dynamic)"
            + "|| @annotation(com.jichangxiu.common.annotation.Dynamic)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Dynamic dynamic = getDynamic(proceedingJoinPoint);
        if (ObjectUtil.isEmpty(dynamic)) {
            // 如果没有获取到 Source 注解什么也不做
            return proceedingJoinPoint.proceed();
        } else {
            return doSourceAround(dynamic, proceedingJoinPoint);
        }
    }

    private Object doSourceAround(Dynamic dynamic, ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 不使用从前台传来的数据源
        // 前台没有传。使用注解配置的
        String code = dynamic.source();
        if (dynamic.before())
            // 需要清空之前的数据源
            DynamicUtils.resetSource();
        else
            // 不需要清空之前的数据源
            if (StrUtil.isEmpty(code))
                // 如果没有获取到新的数据源，那么沿用之前的数据源
                code = DynamicUtils.currentSource();
        // 1：清空了之前的数据源，没有获取到新的数据源
        // 2：没有清空之前的数据源，也没有沿用到有效的之前的数据源
        if (StrUtil.isEmpty(code))
            // 获取当前登录用户的租户数据源
            code = JcxContext.getTenantSource();
        // 如果最后还是没有可用的数据源，会有个默认的本地数据源托底
        if (StrUtil.isEmpty(code))
            code = Constants.DEFAULT_DATA_SOURCE;
        Object object;
        try {
            DynamicUtils.changeSource(code);
            object = proceedingJoinPoint.proceed();
        } finally {
            // 在业务结束之后，判断是否销毁数据库链接
            if (dynamic.after())
                DynamicUtils.resetSource();
        }
        return object;
    }

    private Dynamic getDynamic(ProceedingJoinPoint proceedingJoinPoint) {
        // 获取方法上 Source 注解
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Dynamic dynamic = method.getAnnotation(Dynamic.class);
        // 获取类上的 Source 注解
        if (ObjectUtil.isEmpty(dynamic)) {
            Class<?> classTarget = proceedingJoinPoint.getTarget().getClass();
            dynamic = classTarget.getAnnotation(Dynamic.class);
        }
        return dynamic;
    }

}
